﻿using Mapster;
using WH.Contracts.Systems.Menus;
using WH.Model.Systems;
using WH.Repositories.IRepositories.ISystem;
using WH.Services.BaseService;
using WH.Services.IServices.ISystem;
using Rw.Core.Common.Paging;
using WH.Common.Constant;
using WH.Common.Paging;
using System.Linq.Expressions;

namespace WH.Services.Services.System
{
    public class MenuService : BaseService<MenuEntity>, IMenuService
    {
        private readonly IMenuRepository _menuRepository;
        private readonly IOrganizationRepository _organizationRepository;

        public MenuService(IMenuRepository menuRepository, IOrganizationRepository organizationRepository) : base(menuRepository)
        {
            _menuRepository = menuRepository;
            _organizationRepository = organizationRepository;
        }

        public async Task<IList<AuthOutputDto>> GetAllAuthAsync()
        {
            var list = await _menuRepository.FindAllAsync(x => x.MenuType == 2);

            var res = list.Select(x => new AuthOutputDto
            {
                Id = x.Id ?? "",
                Action = x.Perms ?? "",
                Describe = x.Description ?? "",
                Status = x.Status,
                Type = x.PermsType ?? ""
            }).ToList();

            return res;
        }


        public async Task<IList<MenuOutputDto>> GetMenusAsync(Expression<Func<MenuEntity, bool>>? predicate = default)
        {
            var list = await _menuRepository.FindAllAsync(predicate);

            list = list.OrderByDescending(x => x.SortNo).ToList();

            var data = list.Adapt<IList<MenuOutputDto>>();

            var orgIds = list.Select(m => m.OrganizationId).Distinct().ToList();
            var orgs = await _organizationRepository.FindAllAsync(o => orgIds.Contains(o.Id));

            foreach (var map in data)
            {
                var org = orgs.FirstOrDefault(o => o.Id == map.OrganizationId);
                if (org != null)
                {
                    map.OrganizationName = org.Name;
                }
            }

            var res = GetTreeNode(data, BusinessFunction.TopParentId);

            return res;
        }


        public async Task<IList<MenuOutputDto>> GetMenusAsync(MenuFilter filter)
        {
            var list = await _menuRepository.GetMenusAsync(filter);
            var data = list.Adapt<IList<MenuOutputDto>>();

            var orgIds = list.Select(m => m.OrganizationId).Distinct().ToList();
            var orgs = await _organizationRepository.FindAllAsync(o => orgIds.Contains(o.Id));

            foreach (var map in data)
            {
                var org = orgs.FirstOrDefault(o => o.Id == map.OrganizationId);
                if (org != null)
                {
                    map.OrganizationName = org.Name;
                }
            }

            //var allPids = data.Select(x => x.ParentId).Distinct().ToList();

            //var ids = data.Select(x => x.Id).ToList();

            ////var listPids = data.Entities.Select(x => x.ParentId).ToList();

            //var pids = allPids.Where(x => !ids.Contains(x) && allPids.Contains(x)).ToList();

            var resList = new List<MenuOutputDto>();

            var nodes = GetTreeNode(data, BusinessFunction.TopParentId);
            resList.AddRange(nodes);

            return resList;
        }

        /// <summary>
        /// 生成菜单树
        /// </summary>
        /// <param name="list"></param>
        /// <param name="parentId"></param>
        /// <returns></returns>
        private IList<MenuOutputDto> GetTreeNode(IList<MenuOutputDto> list, string parentId)
        {
            var nodes = list.Where(x => x.ParentId == parentId).ToList();

            foreach (var item in nodes)
            {
                item.Children = GetTreeNode(list, item.Id ?? "");

                if (item.Children.Count > 0)
                {
                    item.IsLeaf = false;
                    item.Leaf = true;
                }
                else
                {
                    item.IsLeaf = true;
                    item.Leaf = false;
                }
            }

            return nodes;
        }

        /// <summary>
        /// 生成菜单树
        /// </summary>
        /// <param name="list"></param>
        /// <param name="parentId"></param>
        /// <returns></returns>
        private async Task<List<MenuOutputDto>> GetTreeNode(string parentId)
        {
            var data = await _menuRepository.FindAllAsync(x => x.ParentId == parentId);
            var nodes = data.Adapt<List<MenuOutputDto>>();

            var orgIds = data.Select(m => m.OrganizationId).Distinct().ToList();
            var orgs = await _organizationRepository.FindAllAsync(o => orgIds.Contains(o.Id));


            foreach (var item in nodes)
            {
                var org = orgs.FirstOrDefault(o => o.Id == item.OrganizationId);
                if (org != null)
                {
                    item.OrganizationName = org.Name;
                }

                item.Children = await GetTreeNode(item.Id ?? "");

                if (item.Children.Count > 0)
                {
                    item.IsLeaf = false;
                    item.Leaf = true;
                }
                else
                {
                    item.IsLeaf = true;
                    item.Leaf = false;
                }
            }

            return nodes;
        }

        public async Task<IPagedList<MenuOutputDto>> GetMenusByPageAsync(PageParam pager, MenuFilter filter)
        {
            var pagedList = await _menuRepository.GetMenusByPageAsync(pager, filter);
            var data = new PagedList<MenuOutputDto>()
            {
                PageIndex = pagedList.PageIndex,
                PageSize = pagedList.PageSize,
                TotalCount = pagedList.TotalCount,
                Entities = pagedList.Entities.Adapt<List<MenuOutputDto>>().ToList()
            };

            var orgIds = data.Entities.Select(m => m.OrganizationId).Distinct().ToList();
            var orgs = await _organizationRepository.FindAllAsync(o => orgIds.Contains(o.Id));

            foreach (var map in data.Entities)
            {
                var org = orgs.FirstOrDefault(o => o.Id == map.OrganizationId);
                if (org != null)
                {
                    map.OrganizationName = org.Name;
                }

                map.Children = await GetTreeNode(map?.Id ?? string.Empty);
            }

            return data;
        }

    }
}
